package com.yunji.storage.event.listener;

import com.yunji.common.constant.LogicCode;
import com.yunji.common.enums.business.StorageType;
import com.yunji.common.model.cache.ProductCacheDTO;
import com.yunji.common.utils.bean.BeanUtils;
import com.yunji.order.consumer.OrderConsumer;
import com.yunji.order.domain.OrderDO;
import com.yunji.order.dto.OrderDetailDTO;
import com.yunji.order.event.OrderStockCreateEvent;
import com.yunji.order.event.OrderStockModifyEvent;
import com.yunji.storage.bo.StockSelectQueryBO;
import com.yunji.storage.dto.StorageProductDTO;
import com.yunji.storage.event.StorageQuantityEvent;
import com.yunji.order.event.OrderStockStatusEvent;
import com.yunji.product.cache.ProductCache;
import com.yunji.storage.bo.StorageRecordsListQueryBO;
import com.yunji.storage.bo.StorageTicketSelectQueryBO;
import com.yunji.storage.context.StorageRecordsBuilder;
import com.yunji.storage.context.StorageTicketBuilder;
import com.yunji.storage.domain.StockDO;
import com.yunji.storage.domain.StorageRecordsDO;
import com.yunji.storage.domain.StorageTicketDO;
import com.yunji.storage.dto.StockDTO;
import com.yunji.storage.dto.StorageOperateDTO;
import com.yunji.storage.enums.StorageBusinessType;
import com.yunji.storage.provide.StockProvide;
import com.yunji.storage.service.IStockService;
import com.yunji.storage.service.IStorageRecordsService;
import com.yunji.storage.service.IStorageTicketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author : peter-zhu
 * @date : 2025/3/17 17:15
 * @description : TODO
 **/
@Component
@Slf4j
public class StorageEventListener {

    @Resource
    protected OrderConsumer orderConsumer;

    @Resource
    protected IStockService stockService;

    @Resource
    protected IStorageRecordsService storageRecordsService;

    @Resource
    protected IStorageTicketService storageTicketService;


    @Transactional(rollbackFor = Exception.class)
    @EventListener
    // 创建订单
    public void handle(OrderStockCreateEvent event){
        OrderDO orderDO = event.getOrderDO();
        StorageTicketDO ticketDO = StorageTicketBuilder.builder().buildOrder(orderDO).build();
        storageTicketService.create(ticketDO);
        List<OrderDetailDTO> detailList = event.getDetailList();
        List<StorageRecordsDO> recordsList = new ArrayList<>();
        for (OrderDetailDTO orderDetailDTO : detailList) {
            ProductCacheDTO product = ProductCache.getProduct(orderDetailDTO.getProductId());
            StorageRecordsDO recordsDO = StorageRecordsBuilder.builder().buildTicket(ticketDO).buildOrder(orderDetailDTO).buildProduct(product).build();
            recordsList.add(recordsDO);
        }
        storageRecordsService.saveBatch(recordsList);
    }

    @Transactional(rollbackFor = Exception.class)
    @EventListener
    // 订单回调
    public void handle(OrderStockModifyEvent event){
        OrderDO orderDO = event.getOrderDO();
        Long belongId = orderDO.getBelongId();
        Long orderId = orderDO.getOrderId();
        String orderCode = orderDO.getOrderCode();
        StorageOperateDTO operateDTO = new StorageOperateDTO();
        operateDTO.setBelongId(belongId);
        operateDTO.setStorageType(StorageType.OUT_STORAGE.getCode());
        operateDTO.setBusinessType(StorageBusinessType.SALES_BUSINESS.getCode());
        operateDTO.setBusinessCode(orderDO.getOrderCode());
        StorageTicketDO vo = orderConsumer.selectStorageTicket(StorageTicketSelectQueryBO.builder().businessId(orderId).businessCode(orderCode).build());
        StorageRecordsListQueryBO recordsParam = new StorageRecordsListQueryBO();
        recordsParam.setTicketId(vo.getTicketId());
        List<StorageRecordsDO> list = orderConsumer.getStorageRecords(recordsParam);
        List<StockDTO> dtoList = new ArrayList<>();
        for (StorageRecordsDO records : list) {
            StockDTO stockDTO = new StockDTO();
            stockDTO.setProductId(records.getProductId());
            stockDTO.setActualQuantity(records.getExpectQuantity());
            dtoList.add(stockDTO);
        }
        operateDTO.setList(dtoList);
        orderConsumer.operateStorage(operateDTO);
    }

    @Transactional(rollbackFor = Exception.class)
    @EventListener
    // 订单回调 退款回调
    public void handle(OrderStockStatusEvent event){
        Long orderId = event.getOrderId();
        String orderCode = event.getOrderCode();
        Integer storageStatus = event.getStorageStatus();
        StorageTicketDO ticketDO = new StorageTicketDO();
        ticketDO.setBusinessType(StorageBusinessType.SALES_BUSINESS.getCode());
        ticketDO.setBusinessId(orderId);
        ticketDO.setBusinessCode(orderCode);
        ticketDO.setUseStatus(LogicCode.NO);
        ticketDO.setStorageStatus(storageStatus);
        orderConsumer.updateStockTicketStatus(ticketDO);
    }


    @Transactional(rollbackFor = Exception.class)
    @EventListener
    // 补偿
    public void handle(StorageQuantityEvent event) {
        List<StorageProductDTO> detailList = event.getDetailList();
        Long belongId = event.getBelongId();
        if (Objects.equals(LogicCode.YES,orderConsumer.selectStockStatus(belongId))) return;
        for (StorageProductDTO dto : detailList) {
            StockDO stockDO = stockService.select(new StockSelectQueryBO(belongId,dto.getProductId()));
            if (BeanUtils.isNotNull(stockDO)) {
                stockDO.setAllStock(stockDO.getAllStock().add(dto.getAllStock()));
                stockDO.setUsableStock(stockDO.getUsableStock().add(dto.getUsableStock()));
                stockDO.setDisableStock(stockDO.getDisableStock().add(dto.getDisableStock()));
                stockDO.setFrozenStock(stockDO.getFrozenStock().add(dto.getFrozenStock()));
                Assert.isTrue(stockService.updateStock(stockDO), "修改失败");
            } else {
                StockDO stock = new StockDO();
                BeanUtils.clone(dto,stock);
                stock.setBelongId(belongId);
                Assert.isTrue(stockService.create(stock), "新增失败");
            }
        }
    }
}
